package jp.syuriken.snsw.lancher;

import gnu.getopt.Getopt;
import gnu.getopt.LongOpt;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Locale;
import java.util.logging.Level;

import jp.syuriken.snsw.terenaibot.BotSystem;
import jp.syuriken.snsw.terenaibot.VersionInfo;
import jp.syuriken.snsw.utils.Logger;
import jp.syuriken.snsw.utils.SimpleLoggerFormatter;
import jp.syuriken.snsw.utils.SimpleLoggerFormatter2;

/**
 * TerenaiBotSystemを起動するためのランチャー。
 * 
 * @author $Author: snswinhaiku.lo@gmail.com $
 */
public class TerenaiBotSystemLancher {
	
	private static class ShutdownHookClass extends Thread {
		
		@Override
		public void run() {
			System.err.println("Shutting down...");
			isFinish = true;
			bt.stopBot();
			try {
				bt.join();
			} catch (InterruptedException e) {
				// do nothing
			}
			try {
				logger.flush();
			} catch (IOException e) {
				System.err.println(e.getLocalizedMessage());
			}
			try {
				logger.close();
			} catch (IOException e) {
				System.err.println(e.getLocalizedMessage());
			}
		}
	}
	

	/** デフォルトログファイル */
	private static final String DEFAULT_LOG_FILENAME = "tbotsys.log";
	
	/** デフォルト設定ファイル */
	private static final String DEFAULT_CONFIG_FILENAME = "tbotsys.cfg";
	
	private static boolean isFinish = false;
	
	private static Logger logger;
	
	private static BotSystem bt;
	
	private static LongOpt[] longOpts = new LongOpt[] {
		new LongOpt("version", LongOpt.NO_ARGUMENT, null, 'v'),
		new LongOpt("help", LongOpt.NO_ARGUMENT, null, 'h'),
		new LongOpt("log-level", LongOpt.REQUIRED_ARGUMENT, null, 'L'),
		new LongOpt("debug", LongOpt.NO_ARGUMENT, null, 'd'),
		new LongOpt("config-file", LongOpt.REQUIRED_ARGUMENT, null, 'c'),
		new LongOpt("log-file", LongOpt.REQUIRED_ARGUMENT, null, 'l'),
		new LongOpt("brief-log", LongOpt.NO_ARGUMENT, null, 'b'),
		new LongOpt("quiet", LongOpt.NO_ARGUMENT, null, 'q')
	};
	

	/**
	 * ヘルプを表示する。
	 */
	private static void help() {
		System.out.println("オプション一覧：");
		System.out.println("  -L  --log-level [LEVEL]  ログに出力するレベルを設定します");
		System.out.println("  -v  --version            バージョンを表示");
		System.out.println("  -h  --help               このヘルプを表示");
		System.out.println("  -d  --debug              デバッグ用 (情報がたくさん流れます)");
		System.out.println("  -c  --config-file [FILE] 設定ファイルを指定する [default=tbotsys.cfg]");
		System.out.println("  -l  --log-file [FILE]    ログファイルを指定する");
		System.out.println("  -b  --brief-log          簡潔なログのみを出力します");
		
	}
	
	/**
	 * バージョンを表示する。
	 */
	private static void helpVersion() {
		
		System.out.println(VersionInfo.getArtifactName() + " (" + VersionInfo.getArtifactId() + " "
				+ VersionInfo.getUniqueVersion() + ")");
		System.out.println("Support URL: " + VersionInfo.getSupportUrl());
		System.out.println();
		System.out.println("Java version: " + System.getProperty("java.version", "<unknown java version>"));
		System.out.println("Java home: " + System.getProperty("java.home", "<unknown java home>"));
		System.out.println("Default locale: " + Locale.getDefault() + ", platform encoding: "
				+ System.getProperty("file.encoding", "<unknown encoding>"));
	}
	
	/**
	* 起動。
	* 
	* @param args オプションを格納した配列。
	*/
	public static void main(String[] args) {
		Getopt options = new Getopt(VersionInfo.getArtifactId(), args, "l:c:L:vhdbq", longOpts);
		int c;
		boolean printVersion = false;
		boolean printHelp = false;
		boolean isDebug = false;
		boolean briefLog = false;
		boolean quietMode = false;
		Level level = Level.FINE;
		String configFile = DEFAULT_CONFIG_FILENAME;
		String logFile = DEFAULT_LOG_FILENAME;
		while ((c = options.getopt()) != -1) {
			switch (c) {
				case 'L':
					try {
						level = Level.parse(options.getOptarg());
					} catch (IllegalArgumentException e) {
						System.err.println(e.getLocalizedMessage());
					}
					break;
				case 'v':
					printVersion = true;
					break;
				case 'h':
					printHelp = true;
					break;
				case 'd':
					isDebug = true;
					break;
				case 'c':
					configFile = options.getOptarg();
					break;
				case 'l':
					logFile = options.getOptarg();
					break;
				case 'b':
					briefLog = true;
					break;
				case 'q':
					quietMode = true;
					break;
				default:
					System.err.println("引数指定の誤り：未知の引数が指定");
			}
		}
		if (printHelp) {
			help();
			return;
		} else if (printVersion) {
			helpVersion();
			return;
		}
		try {
			SimpleLoggerFormatter loggerFormatter = new SimpleLoggerFormatter2();
			loggerFormatter.setDebug(briefLog == false);
			logger = Logger.getLogger(logFile, level, loggerFormatter);
			if (quietMode == false) {
				logger.addWriter(new PrintWriter(System.out));
			}
		} catch (IOException e) {
			System.err.println(e.getLocalizedMessage());
			System.exit(1);
		}
		try {
			bt = BotSystem.getInstance(logger, new File(configFile), isDebug);
		} catch (FileNotFoundException e) {
			logger.log(Level.SEVERE, "設定ファイル" + configFile + "が見つかりません");
			System.exit(1);
		} catch (Exception e) {
			logger.log(Level.SEVERE, e);
			System.exit(1);
		}
		bt.start();
		Runtime.getRuntime().addShutdownHook(new ShutdownHookClass());
		
		do {
			try {
				bt.join();
			} catch (InterruptedException e) {
				// do nothing
			}
		} while (!isFinish);
	}
	
	private TerenaiBotSystemLancher() {
	}
}
